package com.yanqu.road.utils.http;

import com.yanqu.road.utils.string.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class HttpHelper {

    private static final String REQUEST_METHOD_POST = "POST";
    public static final String REQUEST_METHOD_GET = "GET";

    private static Logger logger = LogManager.getLogger(HttpHelper.class.getName());

    //连接超时
    private static int CONNECT_TIME_OUT = 2000;

    //读取数据超时
    private static int READ_TIME_OUT = 2000;

    //请求编码
    private static String REQUEST_ENCODING = "UTF-8";


    public static String doGet(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
        return doRequest(reqUrl, paramMap, REQUEST_METHOD_GET, recvEncoding, true);
    }


    public static String doGet(String reqUrl, String recvEncoding) {
        Map<String, String> paramMap = null;
        String queryUrl = reqUrl;
        int paramIndex = reqUrl.indexOf("?");
        if (paramIndex > 0) {
            paramMap = new HashMap<String, String>();
            queryUrl = reqUrl.substring(0, paramIndex);
            String parameters = reqUrl.substring(paramIndex + 1, reqUrl.length());
            String[] paramArray = parameters.split("&");
            for (int i = 0; i < paramArray.length; i++) {
                String string = paramArray[i];
                int index = string.indexOf("=");
                if (index > 0) {
                    String parameter = string.substring(0, index);
                    String value = string.substring(index + 1, string.length());
                    paramMap.put(parameter, value);
                }
            }
        } else {
            return null;
        }

        return doRequest(queryUrl, paramMap, REQUEST_METHOD_GET, recvEncoding, true);
    }

    public static Map<String, String> httpPostJson(String reqUrl, String jsonContent, String recvEncoding, Map<String, String> headerMap,
                                                   int socketTimeout, int connectTimeout, int connectionRequestTimeout) {
        CloseableHttpClient httpclient = (CloseableHttpClient) getHttpClient();
        Map<String, String> resultMap = new HashMap<>();
        HttpPost httpPost = null;
        CloseableHttpResponse response = null;
        try {
            httpPost = new HttpPost(reqUrl);
            if (!StringUtils.isNullOrEmpty(jsonContent)) {
                StringEntity entity = new StringEntity(jsonContent, recvEncoding);
                entity.setContentEncoding(recvEncoding);
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            if (null != headerMap) {
                for (Entry<String, String> entry : headerMap.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }

            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).
                    setConnectionRequestTimeout(connectionRequestTimeout).build();
            httpPost.setConfig(requestConfig);
            response = httpclient.execute(httpPost);
            int code = response.getStatusLine().getStatusCode();
            resultMap.put("code", "" + code);
            HttpEntity entity = response.getEntity();
            if (null != entity) {
                resultMap.put("body", EntityUtils.toString(entity, recvEncoding));
            } else {
                resultMap.put("body", "");
            }
        } catch (ConnectTimeoutException e) {
            logger.error("ConnectTimeoutException, URL: " + httpPost);
            resultMap.put("code", "" + 408);
        } catch (SocketTimeoutException e) {
            logger.error("SocketTimeoutException, URL: " + httpPost);
            resultMap.put("code", "" + 408);
        } catch (Exception e) {
            logger.error("HttpClient error: ", e);
            resultMap.put("code", "" + 500);
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpPost) {
                httpPost.releaseConnection();
            }
        }
        return resultMap;
    }


    public static String doPost(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
        return doRequest(reqUrl, paramMap, REQUEST_METHOD_POST, recvEncoding, false);
    }


    public static String doRequest(String reqUrl, Map<String, String> paramMap, String reqMethod, String recvEncoding, boolean needURLEncoder) {
        HttpURLConnection urlCon = null;
        String responseContent = null;
        try {
            StringBuilder params = new StringBuilder();
            if (paramMap != null) {
                for (Entry<String, String> element : paramMap.entrySet()) {
                    params.append(element.getKey());
                    params.append("=");
                    if (needURLEncoder) {
                        params.append(URLEncoder.encode(element.getValue(), REQUEST_ENCODING));
                    } else {
                        params.append(element.getValue());
                    }
                    params.append("&");
                }
                if (params.length() > 0) {
                    params = params.deleteCharAt(params.length() - 1);
                }
            }
            URL url = new URL(reqUrl);
            urlCon = (HttpURLConnection) url.openConnection();
            urlCon.setRequestMethod(reqMethod);
            urlCon.setConnectTimeout(5 * 1000);
            urlCon.setReadTimeout(5 * 1000);
            urlCon.setDoOutput(true);
            byte[] b = params.toString().getBytes();
            urlCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            urlCon.setRequestProperty("Content-Length", String.valueOf(b.length));
            OutputStream out = urlCon.getOutputStream();
            out.write(b, 0, b.length);
            out.flush();
            out.close();

            InputStream in = urlCon.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(in, recvEncoding));
            String tempLine = rd.readLine();
            StringBuffer tempStr = new StringBuffer();
            while (tempLine != null) {
                tempStr.append(tempLine);
                tempLine = rd.readLine();
            }
            responseContent = tempStr.toString();
            //    System.out.println("receive:"+responseContent);//sout
            rd.close();
            in.close();

            urlCon.getResponseMessage();
        } catch (IOException e) {
            logger.error("异常错误", e);
            logger.error("urlconnection error , url " + reqUrl, e);
        } finally {
            if (urlCon != null) {
                urlCon.disconnect();
            }
        }
        return responseContent;
    }

    public static void log(StringBuilder sb, String prefix, long end, long start) {
        long t = end - start;
        if (t > 5) {
            sb.append("time cost ====").append(prefix).append(" : ").append((end - start)).append("\n");
        }
    }


    public static Map<String, String> doGet(String reqUrl, Map<String, String> paramMap) {
        Map<String, String> result = null;
        int code = 0;
        String body = "";
        CloseableHttpClient httpclient = (CloseableHttpClient) getHttpClient();
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(reqUrl);
            sb.append("?");
            for (Entry<String, String> param : paramMap.entrySet()) {
                if (param != null) {
                    sb.append(param.getKey());
                    sb.append("=");
                    sb.append(URLEncoder.encode(param.getValue(), "UTF-8"));
                    sb.append("&");
                }
            }
            sb = sb.deleteCharAt(sb.length() - 1);
            HttpGet httpGet = new HttpGet(sb.toString());
            // 配置连接时间
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIME_OUT)
                    .setConnectTimeout(CONNECT_TIME_OUT).setConnectionRequestTimeout(READ_TIME_OUT).build();
            httpGet.setConfig(requestConfig);
            CloseableHttpResponse response = null;

            try {
                response = httpclient.execute(httpGet);
                code = response.getStatusLine().getStatusCode();
                HttpEntity entity = response.getEntity();
                body = EntityUtils.toString(entity);
            } catch (ConnectTimeoutException e) {
                logger.error("ConnectTimeoutException, URL: " + httpGet.getURI().toString());
            } catch (SocketTimeoutException e) {
                logger.error("SocketTimeoutException, URL: " + httpGet.getURI().toString());
            } finally {
                if (response != null) {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                }
                if (httpGet != null) {
                    httpGet.releaseConnection();
                }
            }
        } catch (Exception e) {
            logger.error("HttpClient error: ", e);
        }

        if (code == 0 && body.isEmpty()) {
            return null;
        }

        result = new HashMap<String, String>();
        result.put("code", code + "");
        result.put("body", body);
        return result;
    }

    private static HttpClient _httpClient;

    private static synchronized HttpClient getHttpClient() {
        if (_httpClient == null) {

            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
            cm.setMaxTotal(400);
            cm.setDefaultMaxPerRoute(200);

            _httpClient = HttpClients.custom().setConnectionManager(cm).build();
            return _httpClient;
        }
        return _httpClient;
    }

    public static final String ERROR = "{\"ret\":100}";
    public static final String ConnectTimeOut = "{\"state\":101,\"msg\":\"连接超时\"}";
    public static final String SocketTimeOut = "{\"state\":102,\"msg\":\"响应数据超时\"}";
    public static final String ResponseNull = "{\"state\":102,\"msg\":\"响应数据为空\"}";
    public static final String SYSTEM_ERROR = "{\"state\":500,\"msg\":\"系统错误\"}";


    public static String doPostJson(String reqUrl, String jsonContent, String recvEncoding) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = null;
        try {
            httpPost = new HttpPost(reqUrl);
            if (!StringUtils.isNullOrEmpty(jsonContent)) {
                StringEntity entity = new StringEntity(jsonContent.toString(), recvEncoding);// 解决中文乱码问题
                entity.setContentEncoding(recvEncoding);
                entity.setContentType("application/json");

                httpPost.setEntity(entity);
            }

            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIME_OUT)
                    .setConnectTimeout(CONNECT_TIME_OUT).setConnectionRequestTimeout(READ_TIME_OUT).build();
            httpPost.setConfig(requestConfig);

            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity, recvEncoding);
                return result;
            } else {
                return ERROR;
            }
        } catch (Exception e) {
            if (null != httpPost) {
                httpPost.abort();
            }
            logger.error(e.getMessage(), e);
            return ERROR;
        }
    }

    public static String doPostJson(String reqUrl, String jsonContent, String recvEncoding, Map<String, String> headerMap) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = null;
        try {
            httpPost = new HttpPost(reqUrl);
            if (!StringUtils.isNullOrEmpty(jsonContent)) {
                StringEntity entity = new StringEntity(jsonContent.toString(), recvEncoding);// 解决中文乱码问题
                entity.setContentEncoding(recvEncoding);
                entity.setContentType("application/json");

                httpPost.setEntity(entity);
            }

            if (headerMap != null) {
                for (Entry<String, String> entry : headerMap.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }

            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIME_OUT)
                    .setConnectTimeout(CONNECT_TIME_OUT).setConnectionRequestTimeout(READ_TIME_OUT).build();
            httpPost.setConfig(requestConfig);

            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity, recvEncoding);
                return result;
            } else {
                return ERROR;
            }
        } catch (Exception e) {
            if (null != httpPost) {
                httpPost.abort();
            }
            logger.error(e.getMessage(), e);
            return ERROR;
        }
    }


    public static String doPostJsonTimeOut(String reqUrl, String jsonContent, String recvEncoding, Map<String, String> headerMap) {
        CloseableHttpClient httpclient = (CloseableHttpClient) getHttpClient();
        try {
            HttpPost httpPost = new HttpPost(reqUrl);
            if (!StringUtils.isNullOrEmpty(jsonContent)) {
                StringEntity entity = new StringEntity(jsonContent.toString(), recvEncoding);// 解决中文乱码问题
                entity.setContentEncoding(recvEncoding);
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            if (headerMap != null) {
                for (Entry<String, String> entry : headerMap.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }

            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIME_OUT)
                    .setConnectTimeout(CONNECT_TIME_OUT).setConnectionRequestTimeout(READ_TIME_OUT).build();
            httpPost.setConfig(requestConfig);
            CloseableHttpResponse response = null;
            try {
                response = httpclient.execute(httpPost);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, recvEncoding);
                    return result;
                } else {
                    return ResponseNull;
                }
            } catch (ConnectTimeoutException e) {
                logger.error("ConnectTimeoutException, URL: " + httpPost);
                return ConnectTimeOut;
            } catch (SocketTimeoutException e) {
                logger.error("SocketTimeoutException, URL: " + httpPost);
                return SocketTimeOut;
            } catch (NoHttpResponseException e) {
                logger.warn("NoHttpResponseException, URL: " + httpPost);
                return ResponseNull;
            } finally {
                if (response != null) {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                }
                if (httpPost != null) {
                    httpPost.releaseConnection();
                }
            }
        } catch (Exception e) {
            logger.error("HttpClient error: ", e);
            return SYSTEM_ERROR;
        }
    }

    public static Map<String, String> doGetWithoutQuestionMark(String reqUrl, Map<String, String> paramMap) {
        Map<String, String> result = null;
        int code = 0;
        String body = "";
        CloseableHttpClient httpclient = (CloseableHttpClient) getHttpClient();
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(reqUrl);
            sb.append("&");
            for (Entry<String, String> param : paramMap.entrySet()) {
                if (param != null) {
                    sb.append(param.getKey());
                    sb.append("=");
                    sb.append(URLEncoder.encode(param.getValue(), "UTF-8"));
                    sb.append("&");
                }
            }
            sb = sb.deleteCharAt(sb.length() - 1);
            HttpGet httpGet = new HttpGet(sb.toString());
            // 配置连接时间
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIME_OUT)
                    .setConnectTimeout(CONNECT_TIME_OUT).setConnectionRequestTimeout(READ_TIME_OUT).build();
            httpGet.setConfig(requestConfig);
            CloseableHttpResponse response = null;

            try {
                response = httpclient.execute(httpGet);
                code = response.getStatusLine().getStatusCode();
                HttpEntity entity = response.getEntity();
                body = EntityUtils.toString(entity);
            } catch (ConnectTimeoutException e) {
                logger.error("ConnectTimeoutException, URL: " + httpGet.getURI().toString());
            } catch (SocketTimeoutException e) {
                logger.error("SocketTimeoutException, URL: " + httpGet.getURI().toString());
            } finally {
                if (response != null) {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                }
                if (httpGet != null) {
                    httpGet.releaseConnection();
                }
            }
        } catch (Exception e) {
            logger.error("HttpClient error: ", e);
        }

        if (code == 0 && body.isEmpty()) {
            return null;
        }

        result = new HashMap<String, String>();
        result.put("code", code + "");
        result.put("body", body);
        return result;
    }
}
